/**
 * 2017年11月14日
 */
package exp.algorithm.sic.feature;

import java.util.ArrayList;
import java.util.List;

import exp.algorithm.sic.ScalePeak;
import exp.algorithm.sic.TimeSeries;

/**
 * 特征点检测的,也就是默认寻找Peak的方式,通过寻找极值点
 * @author Alex
 *
 */
public class ExtremePeakFinder implements PeakFinder {

	public static void main(String[] args) {
		ExtremePeakFinder epf = new ExtremePeakFinder();
		TimeSeries tes[] = new TimeSeries[]{
				new TimeSeries(new float[]{0,1,2,3,4,3,1,1,0}),
				new TimeSeries(new float[]{1,2,3,4,5,4,1,2,1}),
				new TimeSeries(new float[]{2,3,4,3,4,3,1,1,0}),
		};
		List<ScalePeak> list = epf.find(0, tes);
		list.forEach(System.out::println);
	}
	
	@Override
	public List<ScalePeak> find(float dogThresh, TimeSeries[] diffImags) {
		ArrayList<ScalePeak> peaks = new ArrayList<ScalePeak>();
		TimeSeries current, above, below;
		// Search the D(k * sigma) to D(2 * sigma) spaces
		for (int level = 1; level < (diffImags.length - 1); level++) {
			current = diffImags[level];
			below = diffImags[level - 1];
			above = diffImags[level + 1];
			peaks.addAll(findPeaks4ThreeLayer(below, current, above, level,dogThresh));
			below = current;
		}
		return (peaks);
		
	}
	private ArrayList<ScalePeak> findPeaks4ThreeLayer(TimeSeries below,
			TimeSeries current, TimeSeries above, int curLev,
			float dogThresh) {
		ArrayList<ScalePeak> peaks = new ArrayList<ScalePeak>();
		//x是寬
		//对于序列,只需要一个层循环就可以
		for (int x = 1; x < (current.width - 1); ++x) {
				RefCheckMark ref = new RefCheckMark();
				ref.isMin = true;
				ref.isMax = true;
				float c = current.data[x]; // 作为中值
				if (Math.abs(c) <= dogThresh)
					continue; // 绝对值小于dogThresh直接过虑，防止大片被高期模糊后的低值点被选中
				checkMinMax(current, c, x, ref, true);
				checkMinMax(below, c, x,  ref, false);
				checkMinMax(above, c, x,  ref, false);
				if (ref.isMin == false && ref.isMax == false)
					continue;
				peaks.add(new ScalePeak(x, curLev));
		}
		return peaks;
	}
	

	/**
	 * 用于传递引用的数据结构
	 */
	static class RefCheckMark {
		boolean isMin;
		boolean isMax;
	}
	private void checkMinMax(TimeSeries layer, float c, int x, RefCheckMark ref, boolean isCurrentLayer) {

		if (layer == null)
			return;

		if (ref.isMin) {
			if (
				layer.data[x - 1] <= c // 左边
				|| (isCurrentLayer ? false : (layer.data[x] < c))// 中间点，如果是当前层直接为false(自己),不是当前层应该小于,没有等于的条件
				|| layer.data[x + 1] <= c // 右边
				)
				ref.isMin = false;
		}
		if (ref.isMax) {
			if (
				layer.data[ x - 1] >= c // 左边
				|| (isCurrentLayer ? false : (layer.data[x] > c)) // 中间点，如果是当前层直接为false(自己),不是当前层应该大于,没有等于的条件
				|| layer.data[x + 1] >= c // 右边
				)
				ref.isMax = false;
		}
	}
}
